#
#
# This program is (c) 2006 by Hochelf <hochelf@gmail.com>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2.1 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. You can also consult
# the terms of the license at:
#
#		<http://www.gnu.org/copyleft/lesser.html>
#
#
# Name:		ngItemSet.tcl
#
# Version:  0.1.7
#
# Description:	NextGen ItemSet System
#
# Author:	Hochelf	<hochelf@gmail.com>
#			AeXu	<info@aexu.li>
#
# Changelog:
#
# v0.1.7 (2006-08-02) - The "cleanup" version
#			Removed useless code
#
# v0.1.6 (2006-04-29) - The "stop the noob" version
#			Added Plevel check which I forgot
#			in previous version.
#
# v0.1.5 (2006-04-29) - The "SQL rocks" version
#			Recoded procedures to use SQL instead
#			of SCP.
#
# v0.1.1 (2006-04-28) - The "call me a script" version
#			Further additions and prepararion for
#			a SQL version.
#
# v0.1.0 (2006-04-27) - The "first try" version.
#			First TCL script with a test SCP file
#
#


#
#	Start-TCL loading order
#
# StartTCL: n
#

package require sqlite3
sqlite3 itemsets "saves/itemsets.db3"

#
#	namespace eval ::ngItemSet
#
# ::ngItemSet namespace and variable definitions
#
namespace eval ::ngItemSet {
	variable NAME "ngItemSet"
	variable VERSION "0.1.7"

	# Trust me, you do NOT want to set DEBUG on...
	variable DEBUG 0
	variable VERBOSE 0

	# SQLdb handle
	variable nghandle "itemsets"

	# Configuration file
	variable conf "scripts/conf/ngItemSet.conf"

	# ItemSet.scp file
	variable itemsetscp "scripts/extra/itemsets.scp"

	# Localization settings
	variable LANG "default"

	# Language strings (en)
	variable c_dbg01 "Enter procedure"

	variable l_hlp01 "NextGen ItemSet System (v%2\$s) - Usage:%1\$c%1\$c%3\$s \[ %4\$s \| %5\$s \]%1\$c%1\$-13s - displays the current program version%1\$c%4\$-15s - shows this info"
	variable l_hlp02 "NextGen ItemSet System (v%2\$s) - Usage:%1\$c%1\$c%3\$s \[ %4\$s \| %5\$s \| %6\$s \| %7\$s \| %8\$s \]%1\$c%4\$-12s - creates a itemset DB with preconfigured sets%1\$c%5\$-15s - deletes the current DB%1\$c%6\$-11s - removes wasted space from the DB%1\$c%7\$-11s - displays the underlying database API version%1\$c%8\$-13s - displays the current program version%1\$c%9\$-15s - shows this info"

	variable l_ver01 "NextGen ItemSet System is at version %s"

	variable l_dba01 "You are not allowed to use this command!"
	variable l_dba02 "NextGen ItemSet System (v%s) database"
	variable l_dba03 "Database cleanup done."
	variable l_dba04 "The tables were successfully deleted."
	variable l_dba05 "The tables were successfully created."
	variable l_dba06 "The tables are already up to date."
	variable l_dba07 "ngItemSet database already exists. If you want to recreate it, use .itemset deletedb first!."
	variable l_dba08 "done"
	variable l_dba09 "Database tables setup %s."

	variable h_elf01 "Itemset"
	variable h_elf02 "added to"
	variable h_elf03 "deleted from"

	variable h_wrk01 "Error in NextGen ItemSet System."

	variable c_sen01 "Unexpected error!"
}

#
#	proc ::ngItemSet::logPrefix { }
#
# Returns a string suitable to add to the console
#
proc ::ngItemSet::logPrefix { } {
	if { [ string length [ info procs "::Custom::LogPrefix" ] ] } {
		return "[ ::Custom::LogPrefix ]ITEMSET:"
	}
	return "[ clock format [ clock seconds ] -format %k:%M:%S ]:M:ITEMSET:"
}

#
#	proc ::ngItemSet::logDebug { }
#
# Returns a debug string to add to the console
#
proc ::ngItemSet::logDebug { } {
	return "[ ::ngItemSet::logPrefix ]DEBUG:"
}

#
#	proc ::ngItemSet::help { player }
#
# Returns a help screen depending on your level (hand called)
#
proc ::ngItemSet::help { player } {
	variable VERSION
	variable DEBUG

	if { $DEBUG } {
		set s_logDEBUG "[ ::ngItemSet::logDebug ] proc help{}:"
		puts "$s_logDEBUG $::ngItemSet::c_dbg01"
	}
	if { [ GetPlevel $player ] < 6 } {
		return [ format $::ngItemSet::l_hlp01 10 $VERSION ".itemset" "version" "help" ]
	} else {
		return [ format $::ngItemSet::l_hlp02 10 $VERSION ".itemset" "createdb" "deletedb" "cleanup" "dbversion" "version" "help" ]
	}
}

#
#	proc ::ngItemSet::version { }
#
# Returns the version info about the plugin (hand called)
#
#
proc ::ngItemSet::version { } {
	variable VERSION
	variable DEBUG

	if { $DEBUG } {
		set s_logDEBUG "[ ::ngItemSet::logDebug ] proc version{}:"
		puts "$s_logDEBUG $;ItemSet::c_dbg01"
	}
	return [ format $::ngItemSet::l_ver01 $VERSION ]
}

#
#	proc ::ngitemSet::createdb
#
# Creation of SQLDB with standard Itemsets
#
proc ::ngItemSet::createdb { player cargs } {
	variable nghandle

	if { [ ::SQLdb::existsSQLdb $nghandle `itemsets` ] } {
		return "$::ngItemSet::l_dba07"
	} else {
		::ngItemSet::InsertSet
		return "$::ngItemSet::l_dba05"
	}
}

#
#	proc ::ngitemSet::deletedb
#
# Deletion of SQLDB
#
proc ::ngItemSet::deletedb { player cargs } {
	variable nghandle

	if { [ ::SQLdb::existsSQLdb $nghandle `itemsets` ] } {
		::SQLdb::querySQLdb $nghandle "DROP TABLE `itemsets`"
		return "$::ngItemSet::l_dba04"
	} else {
		return "$::ngItemSet::l_dba06"
	}
}

#
#	proc ::ngitemSet::scpinsertset
#
# Insert a specific Itemset into SQLDB using SCP file
#
proc ::ngItemSet::InsertSet { } {
  variable nghandle
  variable itemsetscp
  set ngishandle [open $itemsetscp r]

    if { ![ ::SQLdb::existsSQLdb $nghandle `itemsets` ] } {
	::SQLdb::querySQLdb $nghandle "CREATE TABLE `itemsets` (`setid` INTEGER PRIMARY KEY, `sname`  TEXT NOT NULL DEFAULT '', `sitem1` INTEGER DEFAULT '', `sitem2` INTEGER DEFAULT '', `sitem3` INTEGER DEFAULT '', `sitem4` INTEGER DEFAULT '', `sitem5` INTEGER DEFAULT '', `sitem6` INTEGER DEFAULT '', `sitem7` INTEGER DEFAULT '', `sitem8` INTEGER DEFAULT '')"

	while { [eof $ngishandle] != 1 } {
	     gets $ngishandle line
	     set line [split $line =]
	     set hline [string range $line 2 end]

		if { [lindex $hline 0] == "itemset" } {
		    set hline [string range $line 2 [expr ([string length $hline]-1)]]
		    set itemset [lindex $hline 1]
		    set sname ""
		    set sitem1 ""
		    set sitem2 ""
		    set sitem3 ""
		    set sitem4 ""
		    set sitem5 ""
		    set sitem6 ""
		    set sitem7 ""
		    set sitem8 ""
		} else {

		    switch [lindex $line 0] {

			"sname" {
				 set sname [lindex $line 1]
				}
			"sitem1" {
				  set sitem1 [lindex $line 1]
				 }
			"sitem2" {
			  	  set sitem2 [lindex $line 1]
				}
			"sitem3" {
				  set sitem3 [lindex $line 1]
				}
			"sitem4" {
				  set sitem4 [lindex $line 1]
				}
			"sitem5" {
				  set sitem5 [lindex $line 1]
				}
			"sitem6" {
				  set sitem6 [lindex $line 1]
				}
			"sitem7" {
				  set sitem7 [lindex $line 1]
				}
			"sitem8" {
				  set sitem8 [lindex $line 1]
				}
			"" {
			    if { [itemsets eval { SELECT `sname` FROM `itemsets` WHERE `setid` = $itemset }] == "" } {
			        itemsets eval { INSERT INTO `itemsets` (`setid`, `sname`, `sitem1`, `sitem2`, `sitem3`, `sitem4`, `sitem5`, `sitem6`, `sitem7`, `sitem8`) VALUES ($itemset, $sname, $sitem1, $sitem2, $sitem3, $sitem4, $sitem5, $sitem6, $sitem7, $sitem8) }
			    }
			   }
		    }		
		}
	}

      puts "[::Custom::LogPrefixNew]ngItemSet successfully imported!		#"

    }

  close $ngishandle

}

#
#	proc ::ngitemSet::scpremovetset
#
# Delete a specific Itemset from SQLDB using SCP file
#
proc ::ngItemSet::scpremoveset { player cargs } {
	variable nghandle

	if { [ ::SQLdb::existsSQLdb $nghandle `itemsets` ] } {
		itemsets eval { SELECT `sname` FROM `itemsets` WHERE `setid` = $cargs } {
			::SQLdb::querySQLdb $nghandle "DELETE FROM `itemsets` WHERE (`setid` = $cargs)"
			return "Data for Set: $cargs $sname removed."
		}
	} else {
		return "$::ngItemSet::l_dba04"
	}
}

#
#	proc ::ngitemSet::add
#
# Select ItemsIDs from SQL and add them to player
#
proc ::ngItemSet::add { player cargs } {
	variable nghandle

	if { [ ::SQLdb::existsSQLdb $nghandle `itemsets` ] } {
		set pname [ ::GetName $player ]
		itemsets eval { SELECT `sname`, `sitem1`, `sitem2`, `sitem3`, `sitem4`, `sitem5`, `sitem6`, `sitem7`, `sitem8` FROM `itemsets` WHERE `setid` = $cargs } {
		    if { $sitem1 != "" } {
			::AddItem [ ::GetSelection $player ] $sitem1
		    }
		    if { $sitem2 != "" } {
			::AddItem [ ::GetSelection $player ] $sitem2
		    }
		    if { $sitem3 != "" } {
			::AddItem [ ::GetSelection $player ] $sitem3
		    }
		    if { $sitem4 != "" } {
			::AddItem [ ::GetSelection $player ] $sitem4
		    }
		    if { $sitem5 != "" } {
			::AddItem [ ::GetSelection $player ] $sitem5
		    }
		    if { $sitem6 != "" } {
			::AddItem [ ::GetSelection $player ] $sitem6
		    }
		    if { $sitem7 != "" } {
			::AddItem [ ::GetSelection $player ] $sitem7
		    }
		    if { $sitem8 != "" } {
			::AddItem [ ::GetSelection $player ] $sitem8
		    }
			return "$::ngItemSet::h_elf01 $cargs $sname $::ngItemSet::h_elf02 $pname." 
		}
	}
}

#
#	proc ::ngitemSet::del
#
# Select ItemsIDs from SQL and delete them from player
#
proc ::ngItemSet::del { player cargs } {
	variable nghandle

	if { [ ::SQLdb::existsSQLdb $nghandle `itemsets` ] } {
		set pname [ ::GetName $player ]
		itemsets eval { SELECT `sname`, `sitem1`, `sitem2`, `sitem3`, `sitem4`, `sitem5`, `sitem6`, `sitem7`, `sitem8` FROM `itemsets` WHERE `setid` = $cargs } { 
			if {[ConsumeItem [GetSelection $player] $sitem1 1] == 1 } { ConsumeItem [GetSelection $player] $sitem1 1 }
			if {[ConsumeItem [GetSelection $player] $sitem2 1] == 1 } { ConsumeItem [GetSelection $player] $sitem2 1 }
			if {[ConsumeItem [GetSelection $player] $sitem3 1] == 1 } { ConsumeItem [GetSelection $player] $sitem3 1 }
			if {[ConsumeItem [GetSelection $player] $sitem4 1] == 1 } { ConsumeItem [GetSelection $player] $sitem4 1 }
			if {[ConsumeItem [GetSelection $player] $sitem5 1] == 1 } { ConsumeItem [GetSelection $player] $sitem5 1 }
			if {[ConsumeItem [GetSelection $player] $sitem6 1] == 1 } { ConsumeItem [GetSelection $player] $sitem6 1 }
			if {[ConsumeItem [GetSelection $player] $sitem7 1] == 1 } { ConsumeItem [GetSelection $player] $sitem7 1 }
			if {[ConsumeItem [GetSelection $player] $sitem8 1] == 1 } { ConsumeItem [GetSelection $player] $sitem8 1 }
			return "$::ngItemSet::h_elf01 $cargs $sname $::ngItemSet::h_elf03 $pname." 
		}
	}
}

#
#	proc ::ngItemSet::readConf { config }
#
# Internal procedure to read the configuration file and set the system
#
proc ::ngItemSet::readConf { config } {
	variable DEBUG
	variable VERBOSE
	variable LANG

	if { $DEBUG } {
		set s_logDEBUG "[ ::ngItemSet::logDebug ] proc readConf{}:"
		puts "$s_logDEBUG Enter procedure"
	}

	if { [ ::Custom::GetScriptVersion "Custom" ] >= "1.97" } {
		foreach { section data } [ ::Custom::ReadConf $config ] {
			if { [ string tolower $section ] == "global" } {
				foreach { key value } $data {
					set key [ string tolower $key ]

					switch $key {
						"lang" {
							if { [ string tolower $value ] != "default" } {
								set LANG $value
							}
						}
						"debug" {
							if { [ string tolower $value ] != "default" } {
								set DEBUG $value

								if { $DEBUG } {
									set s_logDEBUG "[ ::ngItemSet::logDebug ] proc readConf{}:"
								}
							}
						}
						default {
							if { [ info exists ::ngItemSet::$key ] } {
								if { [ string tolower $value ] != "default" } {
									set ::ngItemSet::$key $value
								}
							}
						}
					}
				}
			}

			set LANG [ expr { [ string tolower $LANG ] == "default" ? "en" : $LANG } ]

			if { [ string tolower $section ] == [ string tolower $LANG ] } {
				foreach { key value } $data {
					set key [ string tolower $key ]

					if { [ info exists ::ngItemSet::$key ] } {
						set ::ngItemSet::$key $value
					}
				}
			}
		}
	} else {
		proc ::ngItemSet::dropNoise { string } {
			variable DEBUG

			if { $DEBUG } {
				set s_logDEBUG "[ ::ngItemSet::logDebug ] proc dropNoise{}:"
				puts "$s_logDEBUG Enter procedure"
			}

			set string [ string trim $string ]

			set comment [ string first "#" $string ]

			if { $comment != -1 } {
				set string [ string trim [ string range $string 0 [ expr { $comment - 1 } ] ] ]
			}

			set comment [ string first "//" $string ]

			if { $comment != -1 } {
				set string [ string trim [ string range $string 0 [ expr { $comment - 1 } ] ] ]
			}

			return $string
		}

		set section -1
		set lines 0

		if { ! [ file exists $config ] } {
			if { $DEBUG } {
				puts "$s_logDEBUG Configuration file \[$config\] missing, setting defaults and language to English."
			} elseif { $VERBOSE } {
				puts "[ ::ngItemSet::logPrefix ] Configuration file \[$config\] missing, setting defaults and language to English."
			}
		} else {
			set f_handle [ open $config ]

			while { ! [ eof $f_handle ] } {
				if { ! [ gets $f_handle s_line ] } {
					continue
				}

				incr lines
				set s_line [ dropNoise $s_line ]

				if { ! [ string length $s_line ] } {
					continue
				}

				if { [ string index $s_line 0 ] == "\[" && [ string index $s_line end ] == "\]"} {
					incr section

					if { [ string tolower [ string trim [ string trim $s_line \[\] ] ] ] == "global" } {
						if { $section } {
							close $f_handle

							if { $DEBUG } {
								puts "$s_logDEBUG Section \[GLOBAL\] from \"$config\" is misplaced, it must be the first section in the file, setting defaults and language to English!"
							} elseif { $VERBOSE } {
								puts "[ ::ngItemSet::logPrefix ] Section \[GLOBAL\] from \"$config\" is misplaced, it must be the first section in the file, setting defaults and language to English!"
							}

							return 0
						}

						while { ! [ eof $f_handle ] } {
							if { ! [ gets $f_handle s_line ] } {
								continue
							}

							incr lines
							set s_line [ dropNoise $s_line ]

							if { ! [ string length $s_line ] } {
								continue
							}

							if { [ string index $s_line 0 ] == "\[" && [ string index $s_line end ] == "\]"} {
								close $f_handle
								set f_handle [ open $config ]
								set lines [ expr { $lines - 1 } ]

								for { set i 0 } { $i < $lines } { incr i } {
									gets $f_handle
								}

								break
							}

							set s_line [ split $s_line "=" ]
							set s_key [ string tolower [ string trim [ lindex $s_line 0 ] ] ]
							set s_value [ string trim [ string trim [ lindex $s_line 1 ] ] \" ]

							if { $DEBUG } {
								puts "$s_logDEBUG s_key=\"$s_key\" s_value=\"$s_value\""
							}

							switch $s_key {
								"lang" {
									set ::ngItemSet::LANG $s_value
								}
								"debug" {
									if { [ string tolower $s_value ] != "default" } {
										set DEBUG $s_value

										if { $DEBUG } {
											set s_logDEBUG "[ ::ngItemSet::logDebug ] proc readConf{}:"
										}
									}
								}
								default {
									if { [ info exists ::ngItemSet::$s_key ] } {
										if { [ string tolower $s_value ] != "default" } {
											set ::ngItemSet::$s_key $s_value
										}
									}
								}
							}
						}

						if { [ eof $f_handle ] } {
							close $f_handle

							if { $DEBUG } {
								puts "$s_logDEBUG End of file reached while reading \[GLOBAL\] from \"$config\", setting defaults and language to English!"
							} elseif { $VERBOSE } {
								puts "[ ::ngItemSet::logPrefix ] End of file reached while reading \[GLOBAL\] from \"$config\", setting defaults and language to English!"
							}

							return 0
						}
					} else {
						if { ! $section } {
							close $f_handle

							if { $DEBUG } {
								puts "$s_logDEBUG Section \[GLOBAL\] from \"$config\" is missing or misplaced, it must be the first section in the file, setting defaults and language to English!"
							} elseif { $VERBOSE } {
								puts "[ ::ngItemSet::logPrefix ] Section \[GLOBAL\] from \"$config\" is missing or misplaced, it must be the first section in the file, setting defaults and language to English!"
							}

							return 0
						}
					}
				}

				if { [ string tolower $::ngItemSet::LANG ] == "default" } {
					close $f_handle

					if { $DEBUG } {
						puts "$s_logDEBUG Setting language defaults to English"
					} elseif { $VERBOSE } {
						puts "[ ::ngItemSet::logPrefix ] Setting language defaults to English"
					}

					return 0
				}

				while { ! [ eof $f_handle ] } {
					if { ! [ gets $f_handle s_line ] } {
						continue
					}

					incr lines
					set s_line [ dropNoise $s_line ]

					if { ! [ string length $s_line ] } {
						continue
					}

					if { [ string index $s_line 0 ] == "\[" && [ string index $s_line end ] == "\]"} {
						if { [ string tolower [ string trim [ string trim $s_line \[\] ] ] ] == [ string tolower $::ngItemSet::LANG ] } {
							break
						}
					}
				}

				if { [ eof $f_handle ] } {
					close $f_handle

					if { $DEBUG } {
						puts "$s_logDEBUG End of file reached while searching for \[[ string toupper $::ngItemSet::LANG ]\] from \"$config\", setting language defaults to English!"
					} elseif { $VERBOSE } {
						puts "[ ::ngItemSet::logPrefix ] End of file reached while searching for \[[ string toupper $::ngItemSet::LANG ]\] from \"$config\", setting language defaults to English!"
					}

					return 0
				}

				while { ! [ eof $f_handle ] } {
					if { ! [ gets $f_handle s_line ] } {
						continue
					}

					incr lines
					set s_line [ dropNoise $s_line ]

					if { ! [ string length $s_line ] } {
						continue
					}

					if { [ string index $s_line 0 ] == "\[" && [ string index $s_line end ] == "\]"} {
						break
					}

					set s_line [ split $s_line "=" ]
					set s_key [ string tolower [ string trim [ lindex $s_line 0 ] ] ]
					set s_value [ string trim [ string trim [ lindex $s_line 1 ] ] \" ]

					if { $DEBUG } {
						puts "$s_logDEBUG s_key=\"$s_key\" s_value=\"$s_value\""
					}

					if { [ info exists ::ngItemSet::$s_key ] } {
						set ::ngItemSet::$s_key $s_value
					}
				}

				break
			}

			close $f_handle
		}
	}
}

#
#	procs ::ngItemSet::commands { }
#
# Internal procedure to create the commands needed to run the script
#
proc ::ngItemSet::itemset { player cargs } {
	variable DEBUG
	variable nghandle "itemsets"

	if { $DEBUG } {
		set s_logDEBUG "[ ::ngItemSet::logDebug ] proc itemset{}:"
		puts "$s_logDEBUG Enter procedure"
	}
	switch [ string tolower [ lindex $cargs 0 ] ] {
		"version" {
			return [ ::ngItemSet::version ]
		}
		"createdb" {
			return [ ::ngItemSet::createdb $player $cargs ]
		}
		"deletedb" {
			return [ ::ngItemSet::deletedb $player $cargs ]
		}
		"dbversion" {
			return [ ::SQLdb::versionSQLdb $nghandle ]
		}
		"cleanup" {
			::SQLdb::cleanupSQLdb itemsets
			return "$::ngItemSet::l_dba03"
		}
		default {
			return [ ::ngItemSet::help $player ]
		}
	}
}

proc ::ngItemSet::itemset_help { player cargs } {
	variable DEBUG

	if { $DEBUG } {
		set s_logDEBUG "[ ::ngItemSet::logDebug ] proc itemset_help{}:"
		puts "$s_logDEBUG Enter procedure"
	}
	return [ ::ngItemSet::help $player ]
}

proc ::ngItemSet::itemset_version { player cargs } {
	variable DEBUG

	if { $DEBUG } {
		set s_logDEBUG "[ ::ngItemSet::logDebug ] proc itemset_version{}:"
		puts "$s_logDEBUG Enter procedure"
	}
	return [ ::ngItemSet::version ]
}


#initialize
proc ::ngItemSet::Init {} {
	::Custom::AddCommand "itemset" "::ngItemSet::itemset" 6
	::Custom::AddCommand "additemset" "::ngItemSet::add" 4
	::Custom::AddCommand "delitemset" "::ngItemSet::del" 4
	::Custom::AddCommand "giveset" "::ngItemSet::add" 4
	::Custom::AddCommand "takeset" "::ngItemSet::del" 4
	::Custom::AddCommand "dbremoveset" "::ngItemSet::scpremoveset" 4
	::ngItemSet::InsertSet
}

::ngItemSet::Init